﻿/*
 * This file is part of CommunitySettlers.
 *
 * CommunitySettlers is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * CommunitySettlers is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with CommunitySettlers.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author: Christoph Husse
 * 
 * Also checkout our homepage: http://communitysettlers.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SettlersEngine
{
    internal class DefaultBuilding : IBuildableObject
    {
        public override event DNotifyHandler<IBuildableObject> OnProductionStarted;
        public override event DNotifyHandler<IBuildableObject> OnProductionReady;

        public DefaultBuilding(RuntimeMap inParent, int inTypeIndex, CyclePoint inInitialPosition)
            : base(inParent, inTypeIndex, inInitialPosition)
        {
            
        }

        public ResourceAnimation Animation
        {
            get
            {
                if (m_AnimationNode == null)
                    return null;

                return m_AnimationNode.Value;
            }

            set
            {
                if (Animation == value)
                    return;

                if (m_AnimationNode != null)
                {
                    Map.UnregisterResourceAnimation(m_AnimationNode);

                    m_AnimationNode = null;
                }

                if (value != null)
                    m_AnimationNode = Map.RegisterResourceAnimation(value);
            }
        }

        public override Boolean IsProducing
        {
            get { return Animation != null; }
        }

        public override Int64 ProductionElapsedMillis
        {
            get
            {
                return (Int64)(Map.AnimationTime.Time.TotalMilliseconds - ProductionStartTime);
            }
        }

        public override Double ProductionProgress
        {
            get
            {
                return Math.Max(Math.Min((Map.AnimationTime.Time.TotalMilliseconds - ProductionStartTime) / Config.ProductionTimeMillis, 1.0), 0.0);
            }
        }

        public override Boolean HasResourceOverflow
        {
            get
            {
                foreach (var prov in Providers)
                {
                    if (prov.Count == prov.MaxStackSize)
                        return true;
                }

                return false;
            }
        }

        public override Boolean HasMissingResources
        {
            get
            {
                int minQuality = 8;
                Boolean result = false;

                // queries are ordered (descendent) by quality index
                foreach (var query in Queries)
                {
                    int qualityIndex = (from e in Config.ResourceStacks where e.Type == query.ResourceType select e.QualityIndex).First();

                    if (minQuality > qualityIndex)
                    {
                        /* 
                         * A lower quality index resets the missing state. If for example "Fish" is missing, with an index of 1,
                         * but there is "Meat" with an index of 0, then the building is still ready to produce! 
                         */
                        result = false;

                        minQuality = qualityIndex;
                    }

                    if (query.Requested == query.MaxStackSize)
                        result = true;

                    if (!result && (qualityIndex > 0))
                        return false; // only check next quality level, if resource is missing
                }

                return result;
            }
        }

        public override Boolean CanProduce
        {
            get
            {
                if (Providers.Count == 0)
                    return false;

                int minQuality = 8;
                Boolean result = true;

                // queries are ordered (descendent) by quality index
                foreach (var query in Queries)
                {
                    int qualityIndex = (from e in Config.ResourceStacks where e.Type == query.ResourceType select e.QualityIndex).First();

                    if (minQuality > qualityIndex)
                    {
                        /* 
                         * A lower quality index resets the missing state. If for example "Fish" is missing, with an index of 1,
                         * but there is "Meat" with an index of 0, then the building is still ready to produce! Would instead
                         * the "Fish" also have an index of 0, then a resource is missing...
                         */
                        result = true;

                        minQuality = qualityIndex;
                    }

                    if (query.Count == 0)
                        result = false;

                    if (result && (qualityIndex > 0))
                        return true; // only check next quality level, if resource was missing
                }

                return result;
            }
        }

        internal override void StartProduction()
        {
            if (Animation != null)
            {
                Animation.Completed();

                Animation = null;
            }

            Animation = new ResourceAnimation(this, AnimationSteps, CycleCounter++);
            Animation.OnCompleted += Animation_OnCompleted;
            ProductionStartTime = Map.AnimationTime.Time.TotalMilliseconds;

            if (OnProductionStarted != null)
                OnProductionStarted(this);
        }

        void Animation_OnCompleted(IPositionProvider inSender)
        {
            Animation = null;
        }

        internal override void CompleteProduction()
        {
            if (Animation != null)
                Animation.Completed();
        }
    }
}
